package com.powerbank.device.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.powerbank.device.dto.DeviceAlertDTO;
import com.powerbank.device.service.DeviceMonitorService;
import com.powerbank.device.service.DeviceHeartbeatService;
import com.powerbank.device.service.EnhancedDeviceCommunicationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 设备监控和报警服务实现类
 */
@Slf4j
@Service
public class DeviceMonitorServiceImpl implements DeviceMonitorService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private DeviceHeartbeatService heartbeatService;

    @Autowired
    private EnhancedDeviceCommunicationService deviceCommunicationService;

    // Redis Key前缀
    private static final String ALERT_KEY_PREFIX = "device:alert:";
    private static final String ACTIVE_ALERTS_KEY = "device:alerts:active";
    private static final String DEVICE_ALERTS_PREFIX = "device:alerts:";

    @Override
    public boolean checkDeviceHealth(String deviceCode) {
        try {
            // 检查设备是否在线
            if (heartbeatService.isDeviceOffline(deviceCode)) {
                log.warn("设备健康检查失败 - 设备离线: {}", deviceCode);
                return false;
            }

            // 检查设备状态缓存
            var deviceStatus = deviceCommunicationService.getCachedDeviceStatus(deviceCode);
            if (deviceStatus != null) {
                // 检查设备状态
                if (deviceStatus.getDeviceStatus() != 1) {
                    log.warn("设备健康检查失败 - 设备状态异常: {}, 状态: {}", deviceCode, deviceStatus.getDeviceStatus());
                    return false;
                }

                // 检查电量
                if (deviceStatus.getBatteryLevel() != null && deviceStatus.getBatteryLevel() < 10) {
                    log.warn("设备健康检查失败 - 设备电量过低: {}, 电量: {}%", deviceCode, deviceStatus.getBatteryLevel());
                    return false;
                }
            }

            log.debug("设备健康检查通过: {}", deviceCode);
            return true;

        } catch (Exception e) {
            log.error("设备健康检查异常 - 设备: {}, 错误: {}", deviceCode, e.getMessage(), e);
            return false;
        }
    }

    @Override
    @Async
    public void createAlert(DeviceAlertDTO alert) {
        try {
            alert.setAlertId(IdUtil.simpleUUID());
            alert.setAlertTime(LocalDateTime.now());
            alert.setAlertStatus(0); // 活跃状态
            alert.setAlertCount(1);
            alert.setLastAlertTime(LocalDateTime.now());

            // 检查是否存在相同类型的活跃报警，避免重复报警
            if (isAlertExists(alert.getDeviceCode(), alert.getAlertType(), alert.getSlotNo())) {
                log.debug("相同类型的报警已存在，跳过创建: 设备={}, 类型={}", alert.getDeviceCode(), alert.getAlertType());
                return;
            }

            // 保存报警到Redis
            String alertKey = ALERT_KEY_PREFIX + alert.getAlertId();
            String alertJson = JSONUtil.toJsonStr(alert);
            redisTemplate.opsForValue().set(alertKey, alertJson, 7, TimeUnit.DAYS);

            // 添加到活跃报警集合
            redisTemplate.opsForSet().add(ACTIVE_ALERTS_KEY, alert.getAlertId());

            // 添加到设备报警列表
            String deviceAlertsKey = DEVICE_ALERTS_PREFIX + alert.getDeviceCode();
            redisTemplate.opsForList().leftPush(deviceAlertsKey, alert.getAlertId());
            redisTemplate.expire(deviceAlertsKey, 30, TimeUnit.DAYS);

            log.info("创建设备报警 - 设备: {}, 类型: {}, 级别: {}, 内容: {}",
                    alert.getDeviceCode(), alert.getAlertType(), alert.getAlertLevel(), alert.getAlertMessage());

            // TODO: 根据报警级别发送通知（邮件、短信、钉钉等）
            sendAlertNotification(alert);

        } catch (Exception e) {
            log.error("创建设备报警失败: {}", e.getMessage(), e);
        }
    }

    @Override
    public List<DeviceAlertDTO> getDeviceAlerts(String deviceCode, int limit) {
        try {
            String deviceAlertsKey = DEVICE_ALERTS_PREFIX + deviceCode;
            List<Object> alertIds = redisTemplate.opsForList().range(deviceAlertsKey, 0, limit - 1);

            List<DeviceAlertDTO> alerts = new ArrayList<>();
            if (alertIds != null) {
                for (Object alertIdObj : alertIds) {
                    String alertKey = ALERT_KEY_PREFIX + alertIdObj.toString();
                    Object alertObj = redisTemplate.opsForValue().get(alertKey);
                    if (alertObj != null) {
                        DeviceAlertDTO alert = JSONUtil.toBean(alertObj.toString(), DeviceAlertDTO.class);
                        alerts.add(alert);
                    }
                }
            }

            return alerts;

        } catch (Exception e) {
            log.error("获取设备报警列表失败 - 设备: {}, 错误: {}", deviceCode, e.getMessage());
            return new ArrayList<>();
        }
    }

    @Override
    public List<DeviceAlertDTO> getActiveAlerts() {
        try {
            Set<Object> activeAlertIds = redisTemplate.opsForSet().members(ACTIVE_ALERTS_KEY);
            List<DeviceAlertDTO> alerts = new ArrayList<>();

            if (activeAlertIds != null) {
                for (Object alertIdObj : activeAlertIds) {
                    String alertKey = ALERT_KEY_PREFIX + alertIdObj.toString();
                    Object alertObj = redisTemplate.opsForValue().get(alertKey);
                    if (alertObj != null) {
                        DeviceAlertDTO alert = JSONUtil.toBean(alertObj.toString(), DeviceAlertDTO.class);
                        if (alert.getAlertStatus() == 0) { // 确认是活跃状态
                            alerts.add(alert);
                        }
                    }
                }
            }

            // 按时间倒序排列
            alerts.sort((a, b) -> b.getAlertTime().compareTo(a.getAlertTime()));
            return alerts;

        } catch (Exception e) {
            log.error("获取活跃报警列表失败: {}", e.getMessage());
            return new ArrayList<>();
        }
    }

    @Override
    public void handleDeviceOfflineAlert(String deviceCode) {
        DeviceAlertDTO alert = new DeviceAlertDTO();
        alert.setDeviceCode(deviceCode);
        alert.setAlertType("OFFLINE");
        alert.setAlertLevel(1); // 严重
        alert.setAlertTitle("设备离线报警");
        alert.setAlertMessage(String.format("设备 %s 已离线，请及时检查设备状态", deviceCode));

        createAlert(alert);
    }

    @Override
    public void handleDeviceErrorAlert(String deviceCode, String errorCode, String errorMessage) {
        DeviceAlertDTO alert = new DeviceAlertDTO();
        alert.setDeviceCode(deviceCode);
        alert.setAlertType("ERROR");
        alert.setAlertLevel(1); // 严重
        alert.setAlertTitle("设备故障报警");
        alert.setAlertMessage(String.format("设备 %s 发生故障：%s", deviceCode, errorMessage));
        alert.setErrorCode(errorCode);

        createAlert(alert);
    }

    @Override
    public void handleLowBatteryAlert(String deviceCode, Integer batteryLevel) {
        DeviceAlertDTO alert = new DeviceAlertDTO();
        alert.setDeviceCode(deviceCode);
        alert.setAlertType("LOW_BATTERY");
        alert.setAlertLevel(2); // 警告
        alert.setAlertTitle("设备电量低报警");
        alert.setAlertMessage(String.format("设备 %s 电量过低：%d%%，请及时充电", deviceCode, batteryLevel));

        createAlert(alert);
    }

    @Override
    public void handleSlotErrorAlert(String deviceCode, Integer slotNo, String errorCode, String errorMessage) {
        DeviceAlertDTO alert = new DeviceAlertDTO();
        alert.setDeviceCode(deviceCode);
        alert.setSlotNo(slotNo);
        alert.setAlertType("SLOT_ERROR");
        alert.setAlertLevel(2); // 警告
        alert.setAlertTitle("插槽故障报警");
        alert.setAlertMessage(String.format("设备 %s 插槽 %d 发生故障：%s", deviceCode, slotNo, errorMessage));
        alert.setErrorCode(errorCode);

        createAlert(alert);
    }

    @Override
    public boolean resolveAlert(String alertId) {
        try {
            String alertKey = ALERT_KEY_PREFIX + alertId;
            Object alertObj = redisTemplate.opsForValue().get(alertKey);

            if (alertObj != null) {
                DeviceAlertDTO alert = JSONUtil.toBean(alertObj.toString(), DeviceAlertDTO.class);
                alert.setAlertStatus(1); // 已解除
                alert.setResolveTime(LocalDateTime.now());

                // 更新报警信息
                String updatedAlertJson = JSONUtil.toJsonStr(alert);
                redisTemplate.opsForValue().set(alertKey, updatedAlertJson, 7, TimeUnit.DAYS);

                // 从活跃报警集合中移除
                redisTemplate.opsForSet().remove(ACTIVE_ALERTS_KEY, alertId);

                log.info("解除设备报警 - 报警ID: {}, 设备: {}", alertId, alert.getDeviceCode());
                return true;
            }

            return false;

        } catch (Exception e) {
            log.error("解除设备报警失败 - 报警ID: {}, 错误: {}", alertId, e.getMessage());
            return false;
        }
    }

    @Override
    public int batchResolveAlerts(List<String> alertIds) {
        int successCount = 0;
        for (String alertId : alertIds) {
            if (resolveAlert(alertId)) {
                successCount++;
            }
        }
        log.info("批量解除报警完成 - 总数: {}, 成功: {}", alertIds.size(), successCount);
        return successCount;
    }

    @Override
    public void startMonitoring() {
        log.info("设备监控服务已启动");
    }

    @Override
    public void stopMonitoring() {
        log.info("设备监控服务已停止");
    }

    /**
     * 定时监控任务（每5分钟执行一次）
     */
    @Scheduled(fixedRate = 300000)
    public void monitorDevices() {
        try {
            log.debug("开始执行设备监控任务");

            // 获取所有在线设备并检查健康状态
            // TODO: 从数据库获取设备列表
            // 这里暂时使用Redis中的在线设备列表
            Set<Object> onlineDevices = redisTemplate.opsForSet().members("device:online:set");
            if (onlineDevices != null) {
                for (Object deviceObj : onlineDevices) {
                    String deviceCode = deviceObj.toString();
                    if (!checkDeviceHealth(deviceCode)) {
                        log.warn("设备健康检查失败，将生成相应报警: {}", deviceCode);
                    }
                }
            }

            log.debug("设备监控任务执行完成");

        } catch (Exception e) {
            log.error("设备监控任务执行失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 检查是否存在相同类型的活跃报警
     */
    private boolean isAlertExists(String deviceCode, String alertType, Integer slotNo) {
        try {
            String deviceAlertsKey = DEVICE_ALERTS_PREFIX + deviceCode;
            List<Object> alertIds = redisTemplate.opsForList().range(deviceAlertsKey, 0, 10); // 检查最近10条

            if (alertIds != null) {
                for (Object alertIdObj : alertIds) {
                    String alertKey = ALERT_KEY_PREFIX + alertIdObj.toString();
                    Object alertObj = redisTemplate.opsForValue().get(alertKey);
                    if (alertObj != null) {
                        DeviceAlertDTO existingAlert = JSONUtil.toBean(alertObj.toString(), DeviceAlertDTO.class);
                        if (existingAlert.getAlertStatus() == 0 && // 活跃状态
                            alertType.equals(existingAlert.getAlertType()) &&
                            (slotNo == null || slotNo.equals(existingAlert.getSlotNo()))) {
                            return true;
                        }
                    }
                }
            }

            return false;

        } catch (Exception e) {
            log.error("检查报警是否存在失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 发送报警通知
     */
    @Async
    private void sendAlertNotification(DeviceAlertDTO alert) {
        try {
            // TODO: 实现具体的通知发送逻辑
            // 1. 邮件通知
            // 2. 短信通知
            // 3. 钉钉/企业微信通知
            // 4. 推送到管理后台

            log.info("发送报警通知 - 设备: {}, 类型: {}, 级别: {}",
                    alert.getDeviceCode(), alert.getAlertType(), alert.getAlertLevel());

        } catch (Exception e) {
            log.error("发送报警通知失败: {}", e.getMessage(), e);
        }
    }
}